package cn.com.zzl.util;

import org.apache.commons.lang3.StringUtils;

import java.util.Arrays;
import java.util.Calendar;

/**
 * Description：编号规则生成器（改良版）
 * Created by 朱正磊 on 2017-07-04 18:12.
 */
public class CodeGeneratorPlus {

	/**
	 * 说明：CR + yyyyMM + 6位流水号，比如 CR201707000001
	 * @Desc 线索客户编号规则前缀
	 */
	public static final String CLUE_CUSTOMER_PREFIX = "CR";

	/**
	 * 说明：HHR + yyyyMMdd + 3位流水号，比如 HHR20170707001
	 * @Desc 城市合伙人编号规则前缀
	 */
	public static final String CITY_PARTNER_PREFIX = "HHR";

	/**
	 * 说明：J + yyyyMM + 3位流水号，比如 J201707001
	 * @Desc 客服记录单编号规则前缀
	 */
	public static final String RECORD_SHEET_PREFIX = "J";

	/**
	 * 说明：K + yyyyMM + 3位流水号，比如 K201707001
	 * @Desc 客诉单编号规则前缀
	 */
	public static final String COMPLAINT_PREFIX = "K";

	/**
	 * 说明：H + yyyyMM + 3位流水号，比如 H201707001
	 * @Desc 回访单编号规则前缀
	 */
	public static final String RETURN_PREFIX = "H";

	/**
	 * 说明：C + yyyyMMdd + 3位流水号，比如 C20170707001
	 * @Desc 客诉单内容编号规则前缀
	 */
	public static final String CONTENT_PREFIX = "C";

	/**
	 * 说明：F + yyyyMMdd + 3位流水号，比如 F20170707001
	 * @Desc 客诉单内容反馈编号规则前缀
	 */
	public static final String FEEDBACK_PREFIX = "F";

	/**
	 * 说明：SH + yyyyMMdd + 4位流水号，比如SH201702100001
	 * @Desc 售后回访编号前缀
	 */
	public static final String SHHF_PREFIX = "SH";

	/**
	 * 说明：TS + yyyyMMdd + 4位流水号，比如TS201702100001
	 * @Desc 投诉处理编号前缀
	 */
	public static final String TSCL_PREFIX = "TS";

	/**
	 * 说明：TD + yyyyMMdd + 4位流水号，比如TD201702100001
	 * @Desc 退订处理编号前缀
	 */
	public static final String TDCL_PREFIX = "TD";

	/**
	 * 说明：HR + yyyyMMdd + 4位流水号，比如HR201702100001
	 * @Desc 呼入跟进编号前缀
	 */
	public static final String HRGJ_PREFIX = "HR";

	//包含年月的编号：线索客户、客服记录单、客诉单、回访单
	private static final String[] yearMonthArray = {
			CLUE_CUSTOMER_PREFIX, RECORD_SHEET_PREFIX, COMPLAINT_PREFIX, RETURN_PREFIX };

	//包含年月日的编号：城市合伙人、客诉单内容、客诉单内容反馈、售后回访、投诉处理、
	//退订处理、呼入跟进
	private static final String[] yearMonthDayArray = {
			CITY_PARTNER_PREFIX, CONTENT_PREFIX, FEEDBACK_PREFIX, SHHF_PREFIX, TSCL_PREFIX,
			TDCL_PREFIX, HRGJ_PREFIX };

	//流水号是3位的编号：城市合伙人、客服记录单、客诉单、回访单、
	//客诉单内容、客诉单内容反馈
	private static final String[] serialNoThreeArray = {
			CITY_PARTNER_PREFIX, RECORD_SHEET_PREFIX, COMPLAINT_PREFIX, RETURN_PREFIX,
			CONTENT_PREFIX, FEEDBACK_PREFIX };

	//流水号是4位的编号：售后回访、投诉处理、退订处理、呼入跟进
	private static final String[] serialNoFourArray = {
			SHHF_PREFIX, TSCL_PREFIX, TDCL_PREFIX, HRGJ_PREFIX };

	//流水号是6位的编号：线索客户
	private static final String[] serialNoSixArray = {
			CLUE_CUSTOMER_PREFIX };

	/**
	 * @Desc 获取下一个流水号
	 * @param prefix 规则前缀
	 * @param maxSerialNo 最大流水号
	 * @return 返回下一个流水号
	 */
	public static String getSerialNo(String prefix, String maxSerialNo) {
		String serialNo = "";
		if (Arrays.asList(serialNoSixArray).contains(prefix)) {
			if (StringUtils.isBlank(maxSerialNo)) {//最大流水号不存在
				serialNo = "000001";//默认生成000001
			} else {
				serialNo = String.format("%06d", Integer.valueOf(maxSerialNo) + 1);
			}
		} else if (Arrays.asList(serialNoThreeArray).contains(prefix)) {
			if (StringUtils.isBlank(maxSerialNo)) {//最大流水号不存在
				serialNo = "001";//默认生成001
			} else {
				serialNo = String.format("%03d", Integer.valueOf(maxSerialNo) + 1);
			}
		} else if (Arrays.asList(serialNoFourArray).contains(prefix)) {
			if (StringUtils.isBlank(maxSerialNo)) {//最大流水号不存在
				serialNo = "0001";//默认生成0001
			} else {
				serialNo = String.format("%04d", Integer.valueOf(maxSerialNo) + 1);
			}
		}
		return serialNo;
	}

	/**
	 * @Desc 获取规则编号
	 * @param prefix 编号前缀
	 * @param yearMonth 年月字符串，比如："201708"
	 * @param yearMonthDay 年月日字符串，比如："20170826"
	 * @param serialNo 流水号
	 * @return 返回规则编号
	 */
	public static String getCode(String prefix, String yearMonth, String yearMonthDay, String serialNo) {
		String code = "";//规则编号
		if (Arrays.asList(yearMonthArray).contains(prefix)) {
			code = prefix + yearMonth + serialNo;
		} else if (Arrays.asList(yearMonthDayArray).contains(prefix)) {
			code = prefix + yearMonthDay + serialNo;
		}
		return code;
	}

	/**
	 * @Desc 获取年月
	 * @return 返回格式 yyyyMM
	 */
	public static String getCurrentYearMonth() {
		Calendar calendar = Calendar.getInstance();
		int year = calendar.get(Calendar.YEAR);
		int month = calendar.get(Calendar.MONTH) + 1;
		return year + "" + ( month < 10 ? "0" + month : month);
	}

	/**
	 * @Desc 获取年月日
	 * @return 返回格式 yyyyMMdd
	 */
	public static String getCurrentYearMonthDay() {
		Calendar calendar = Calendar.getInstance();
		int year = calendar.get(Calendar.YEAR);
		int month = calendar.get(Calendar.MONTH) + 1;
		int day = calendar.get(Calendar.DAY_OF_MONTH);
		return year + "" + (month < 10 ? "0" + month : month) + "" + (day < 10 ? "0" + day : day);
	}

	/**
	 * @Desc 根据编号前缀获取当前日期字符串，可能是年月，也可能是年月日
	 * @param prefix 编号前缀
	 * @return 返回当前日期字符串：例如"201708"，或者"20170826"
	 */
	private static String getDateNum(String prefix, String yearMonth, String yearMonthDay) {
		String dateNum = "";
		if (Arrays.asList(yearMonthArray).contains(prefix)) {
			dateNum = yearMonth;
		} else if (Arrays.asList(yearMonthDayArray).contains(prefix)) {
			dateNum = yearMonthDay;
		}
		return dateNum;
	}

	/**
	 * @Desc 获取与规则编号相关的数据数组
	 * @param prefix 前缀
	 * @param object 对象
	 * @param methodName 方法名
	 * @param mapper mapper方法名
	 * @return 返回值是一个code、dateNum、serialNo组成的字符串数组
	 */
	public static String[] getCodeInfo(String prefix, Object object, String methodName, String mapper) {
		String yearMonth = getCurrentYearMonth();//当前年月字符串
		String yearMonthDay = getCurrentYearMonthDay();//当前年月日字符串
		Class<?>[] classes = new Class[]{String.class, Object.class};//参数类型数组
		Object[] params = new Object[2];//参数值数组
		params[0] = mapper;//第一个参数，mapper方法名
		String dateNum = getDateNum(prefix, yearMonth, yearMonthDay);
		params[1] = dateNum;//第二个参数，当前日期字符串
		String maxSerialNo = (String) ReflectUtil.invoke(object, methodName, classes, params);//数据库已存在最大流水号
		String serialNo = getSerialNo(prefix, maxSerialNo);//获取当前编号需要的流水号
		String code = getCode(prefix, yearMonth, yearMonthDay, serialNo);//编号、日期数组
		return new String[]{code, dateNum, serialNo};//编号、日期、流水号数组
	}

	/**
	 * @Desc 测试编号规则生成方式是否正确
	 * @param args main默认参数
	 */
	public static void main(String[] args) {
		String prefix = CodeGenerator.CLUE_CUSTOMER_PREFIX;
		//第一次为null（从数据库里根据条件查流水号，不建议使用count(*)来查询因为数据有删减，建议使用max()函数）
		String maxSerialNo = "000001";
		String serialNo = CodeGenerator.getSerialNo(prefix, maxSerialNo);
		String yearMonth = CodeGenerator.getCurrentYearMonth();
		String code = CodeGenerator.getCode(prefix, yearMonth, null, serialNo);
		System.out.println(code);

		String prefix2 = CodeGenerator.CITY_PARTNER_PREFIX;
		//第一次为null（从数据库里根据条件查流水号，不建议使用count(*)来查询因为数据有删减，建议使用max()函数）
		String maxSerialNo2 = "001";
		String serialNo2 = CodeGenerator.getSerialNo(prefix2, maxSerialNo2);
		String yearMonthDay = CodeGenerator.getCurrentYearMonthDay();
		String code2 = CodeGenerator.getCode(prefix2, null, yearMonthDay, serialNo2);
		System.out.println(code2);

		//String[] complaintCodeInfo = getCodeInfo(COMPLAINT_PREFIX, daoSupport, "findForObject", "ComplaintMapper.findMaxSerialNo");
	}

}
